import fs from 'fs';
import path from 'path';
import { v4 as uuidv4 } from 'uuid';
import multer from 'multer';
import sharp from 'sharp';
import { Request } from 'express';
import config from '../config/upload';

/**
 * 上传文件的配置信息
 */
interface FileUploadConfig {
  allowedTypes: string[];
  maxSize: number;
  uploadDir: string;
  thumbnailDir: string;
}

/**
 * 上传文件的结果
 */
interface UploadResult {
  success: boolean;
  fileName?: string;
  fileUrl?: string;
  thumbnailUrl?: string;
  error?: string;
  size?: number;
  mimetype?: string;
}

/**
 * 上传文件服务
 * @description 处理文件上传、图片处理等功能
 */
class UploadService {
  private readonly fileConfig: FileUploadConfig;
  private readonly imageConfig: FileUploadConfig;

  constructor() {
    // 文件上传配置
    this.fileConfig = {
      allowedTypes: config.file.allowedTypes,
      maxSize: config.file.maxSize,
      uploadDir: config.file.uploadDir,
      thumbnailDir: '',
    };

    // 图片上传配置
    this.imageConfig = {
      allowedTypes: config.image.allowedTypes,
      maxSize: config.image.maxSize,
      uploadDir: config.image.uploadDir,
      thumbnailDir: config.image.thumbnailDir,
    };

    // 确保上传目录存在
    this.ensureDirectories();
  }

  /**
   * 确保上传目录存在
   */
  private ensureDirectories(): void {
    // 确保文件上传目录存在
    if (!fs.existsSync(this.fileConfig.uploadDir)) {
      fs.mkdirSync(this.fileConfig.uploadDir, { recursive: true });
    }

    // 确保图片上传目录存在
    if (!fs.existsSync(this.imageConfig.uploadDir)) {
      fs.mkdirSync(this.imageConfig.uploadDir, { recursive: true });
    }

    // 确保缩略图目录存在
    if (!fs.existsSync(this.imageConfig.thumbnailDir)) {
      fs.mkdirSync(this.imageConfig.thumbnailDir, { recursive: true });
    }
  }

  /**
   * 创建文件存储配置
   * @param isImage 是否为图片文件
   * @returns multer存储配置
   */
  private createStorage(isImage: boolean): multer.StorageEngine {
    const uploadConfig = isImage ? this.imageConfig : this.fileConfig;

    return multer.diskStorage({
      destination: (req, file, cb) => {
        cb(null, uploadConfig.uploadDir);
      },
      filename: (req, file, cb) => {
        // 生成文件名: uuid + 原始扩展名
        const fileExt = path.extname(file.originalname);
        const fileName = `${uuidv4()}${fileExt}`;
        cb(null, fileName);
      },
    });
  }

  /**
   * 文件过滤器
   * @param isImage 是否为图片文件
   * @returns 文件过滤函数
   */
  private createFileFilter(isImage: boolean) {
    const uploadConfig = isImage ? this.imageConfig : this.fileConfig;

    return (req: Request, file: Express.Multer.File, cb: multer.FileFilterCallback) => {
      // 检查文件类型
      if (!uploadConfig.allowedTypes.includes(file.mimetype)) {
        return cb(new Error(`不支持的文件类型: ${file.mimetype}`));
      }

      // 检查文件大小 (multer会在storage前调用fileFilter)
      // 此处无法直接获取文件大小，需要在上传后再次检查
      cb(null, true);
    };
  }

  /**
   * 获取图片上传中间件
   * @returns multer中间件
   */
  public getImageUploadMiddleware() {
    const storage = this.createStorage(true);
    const fileFilter = this.createFileFilter(true);

    return multer({
      storage,
      fileFilter,
      limits: {
        fileSize: this.imageConfig.maxSize,
      },
    });
  }

  /**
   * 获取文件上传中间件
   * @returns multer中间件
   */
  public getFileUploadMiddleware() {
    const storage = this.createStorage(false);
    const fileFilter = this.createFileFilter(false);

    return multer({
      storage,
      fileFilter,
      limits: {
        fileSize: this.fileConfig.maxSize,
      },
    });
  }

  /**
   * 处理上传的图片
   * @param file 上传的文件
   * @returns 处理结果
   */
  public async processUploadedImage(file: Express.Multer.File): Promise<UploadResult> {
    try {
      if (!file) {
        return { success: false, error: '没有上传文件' };
      }

      // 检查文件类型
      if (!this.imageConfig.allowedTypes.includes(file.mimetype)) {
        // 删除不符合类型的文件
        fs.unlinkSync(file.path);
        return { success: false, error: `不支持的文件类型: ${file.mimetype}` };
      }

      // 检查文件大小
      if (file.size > this.imageConfig.maxSize) {
        // 删除超过大小限制的文件
        fs.unlinkSync(file.path);
        return {
          success: false,
          error: `文件过大，最大支持 ${this.imageConfig.maxSize / (1024 * 1024)} MB`,
        };
      }

      // 生成缩略图
      const thumbnailPath = path.join(this.imageConfig.thumbnailDir, file.filename);
      await this.generateThumbnail(file.path, thumbnailPath);

      // 构建文件URL
      const baseUrl = config.baseUrl || '';
      const fileUrl = `${baseUrl}/uploads/images/${file.filename}`;
      const thumbnailUrl = `${baseUrl}/uploads/images/thumbnails/${file.filename}`;

      return {
        success: true,
        fileName: file.filename,
        fileUrl,
        thumbnailUrl,
        size: file.size,
        mimetype: file.mimetype,
      };
    } catch (error) {
      // 发生错误时清理文件
      if (file && fs.existsSync(file.path)) {
        fs.unlinkSync(file.path);
      }

      const thumbnailPath = path.join(this.imageConfig.thumbnailDir, file?.filename || '');
      if (fs.existsSync(thumbnailPath)) {
        fs.unlinkSync(thumbnailPath);
      }

      return {
        success: false,
        error: error instanceof Error ? error.message : '处理图片时发生未知错误',
      };
    }
  }

  /**
   * 处理上传的文件
   * @param file 上传的文件
   * @returns 处理结果
   */
  public async processUploadedFile(file: Express.Multer.File): Promise<UploadResult> {
    try {
      if (!file) {
        return { success: false, error: '没有上传文件' };
      }

      // 检查文件类型
      if (!this.fileConfig.allowedTypes.includes(file.mimetype)) {
        // 删除不符合类型的文件
        fs.unlinkSync(file.path);
        return { success: false, error: `不支持的文件类型: ${file.mimetype}` };
      }

      // 检查文件大小
      if (file.size > this.fileConfig.maxSize) {
        // 删除超过大小限制的文件
        fs.unlinkSync(file.path);
        return {
          success: false,
          error: `文件过大，最大支持 ${this.fileConfig.maxSize / (1024 * 1024)} MB`,
        };
      }

      // 构建文件URL
      const baseUrl = config.baseUrl || '';
      const fileUrl = `${baseUrl}/uploads/files/${file.filename}`;

      return {
        success: true,
        fileName: file.filename,
        fileUrl,
        size: file.size,
        mimetype: file.mimetype,
      };
    } catch (error) {
      // 发生错误时清理文件
      if (file && fs.existsSync(file.path)) {
        fs.unlinkSync(file.path);
      }

      return {
        success: false,
        error: error instanceof Error ? error.message : '处理文件时发生未知错误',
      };
    }
  }

  /**
   * 生成缩略图
   * @param sourcePath 源文件路径
   * @param targetPath 目标文件路径
   */
  private async generateThumbnail(sourcePath: string, targetPath: string): Promise<void> {
    try {
      // 使用sharp生成缩略图
      await sharp(sourcePath)
        .resize(200, 200, {
          fit: 'inside',
          withoutEnlargement: true,
        })
        .toFile(targetPath);
    } catch (error) {
      throw new Error(`生成缩略图失败: ${error instanceof Error ? error.message : '未知错误'}`);
    }
  }

  /**
   * 删除文件
   * @param fileName 文件名
   * @param isImage 是否为图片
   * @returns 是否删除成功
   */
  public async deleteFile(fileName: string, isImage: boolean): Promise<boolean> {
    try {
      const uploadConfig = isImage ? this.imageConfig : this.fileConfig;
      const filePath = path.join(uploadConfig.uploadDir, fileName);

      // 检查文件是否存在
      if (!fs.existsSync(filePath)) {
        return false;
      }

      // 删除文件
      fs.unlinkSync(filePath);

      // 如果是图片，还需要删除缩略图
      if (isImage) {
        const thumbnailPath = path.join(this.imageConfig.thumbnailDir, fileName);
        if (fs.existsSync(thumbnailPath)) {
          fs.unlinkSync(thumbnailPath);
        }
      }

      return true;
    } catch (error) {
      console.error('删除文件失败:', error);
      return false;
    }
  }
}

export default new UploadService();
